home *** CD-ROM | disk | FTP | other *** search
/ NOVA - For the NeXT Workstation / NOVA - For the NeXT Workstation.iso / SourceCode / AdobeExamples / NX_Scroll / DocView.m < prev    next >
Text File  |  1992-12-19  |  11KB  |  430 lines

  1.  
  2. /*
  3.  * (a)  (C) 1990 by Adobe Systems Incorporated. All rights reserved.
  4.  *
  5.  * (b)  If this Sample Code is distributed as part of the Display PostScript
  6.  *    System Software Development Kit from Adobe Systems Incorporated,
  7.  *    then this copy is designated as Development Software and its use is
  8.  *    subject to the terms of the License Agreement attached to such Kit.
  9.  *
  10.  * (c)  If this Sample Code is distributed independently, then the following
  11.  *    terms apply:
  12.  *
  13.  * (d)  This file may be freely copied and redistributed as long as:
  14.  *    1) Parts (a), (d), (e) and (f) continue to be included in the file,
  15.  *    2) If the file has been modified in any way, a notice of such
  16.  *      modification is conspicuously indicated.
  17.  *
  18.  * (e)  PostScript, Display PostScript, and Adobe are registered trademarks of
  19.  *    Adobe Systems Incorporated.
  20.  * 
  21.  * (f) THE INFORMATION BELOW IS FURNISHED AS IS, IS SUBJECT TO
  22.  *    CHANGE WITHOUT NOTICE, AND SHOULD NOT BE CONSTRUED
  23.  *    AS A COMMITMENT BY ADOBE SYSTEMS INCORPORATED.
  24.  *    ADOBE SYSTEMS INCORPORATED ASSUMES NO RESPONSIBILITY
  25.  *    OR LIABILITY FOR ANY ERRORS OR INACCURACIES, MAKES NO
  26.  *    WARRANTY OF ANY KIND (EXPRESS, IMPLIED OR STATUTORY)
  27.  *    WITH RESPECT TO THIS INFORMATION, AND EXPRESSLY
  28.  *    DISCLAIMS ANY AND ALL WARRANTIES OF MERCHANTABILITY, 
  29.  *    FITNESS FOR PARTICULAR PURPOSES AND NONINFRINGEMENT
  30.  *    OF THIRD PARTY RIGHTS.
  31.  */
  32.  
  33. /*
  34.  *    DocView.m
  35.  *
  36.  *    This class handles the scaling of the drawing view. It repositions
  37.  *    The drawing view within itself if the drawing view is smaller than the
  38.  *    size of the clip view. The size of the doc view is:
  39.  *    MAX(clip view frame, drawing view frame).
  40.  *
  41.  *    Version:    2.0
  42.  *    Author:    Ken Fromm
  43.  *    History:
  44.  *            03-07-91        Added this comment.
  45.  */
  46.  
  47. #import "DocView.h"
  48.  
  49. #import <appkit/NXCursor.h>
  50. #import <appkit/NXImage.h>
  51. #import <appkit/Matrix.h>
  52. #import <appkit/ScrollView.h>
  53. #import <dpsclient/wraps.h>
  54. #import <appkit/nextstd.h>
  55.  
  56. @implementation DocView
  57.  
  58. /*
  59. *    Since there is only one subview its easier to keep track of it as an
  60. *    instance variable rather than in the subview list.  Returns any the
  61. *    previous drawing view.
  62. */
  63. - setDrawView:subView
  64. {
  65.     id        oldView;
  66.  
  67.     oldView = drawviewId;
  68.     [oldView  removeFromSuperview];
  69.  
  70.     [self  addSubview:subView];
  71.     drawviewId = subView;
  72.     
  73.     return oldView;
  74. }
  75.  
  76. - drawView;
  77. {
  78.     return drawviewId;
  79. }
  80.  
  81. - setZoomControl:anObject
  82. {
  83.     zoomControl = anObject;
  84.     
  85.     return self;
  86. }
  87.  
  88. - zoomControl
  89. {
  90.     return zoomControl;
  91. }
  92.  
  93. - setHitSetting:(float) value
  94. {    
  95.     hitsetting = value;
  96.  
  97.     return self;    
  98. }
  99.  
  100. /*
  101. *    Scale the hit setting. Using an unscaled hit setting would be like
  102. *    using a boxing glove on a 400% scale.
  103. */
  104. - (float) hitSetting
  105. {    
  106.     return hitsetting * (1.0/scale);
  107. }
  108.  
  109. - setScale:(float)value
  110. {
  111.     scale = value;
  112.     
  113.     return self;
  114. }
  115.  
  116. - (float) scale
  117. {
  118.     return  scale;
  119. }
  120.  
  121. - (BOOL) isZooming
  122. {
  123.     return zooming;
  124. }
  125.  
  126. /*
  127. *    Check whether the frame of the drawingview is in the rectangle passed in.
  128. *    If drop is true, then include the linewidth and the drop shadow as part of the
  129. *    drawingview frame.
  130. */
  131. - getDrawViewInRect:(const NXRect *) aRect  withDrop:(BOOL) drop
  132. {
  133.     id        aView = NULL;
  134.  
  135.     NXRect    viewRect, dropRect;
  136.     
  137.     [drawviewId  getFrame:&viewRect];
  138.     if (drop)
  139.     {    
  140.         dropRect = viewRect;
  141.         NXOffsetRect(&dropRect, rint(OFFSET * scale), rint(-OFFSET * scale));
  142.         NXOffsetRect(&viewRect, rint(LINEWIDTH/2 * scale), rint(LINEWIDTH/2 * scale));
  143.         NXUnionRect(&dropRect, &viewRect);
  144.     }
  145.     if (NXIntersectsRect(aRect, &viewRect))
  146.         aView = drawviewId;
  147.  
  148.     return  aView;
  149. }
  150.  
  151. /*
  152. *    This method is overridden from the View class. When the
  153. *    user is zooming the cursor rect for the zoom cursor is set
  154. *    the the frame of the drawing view.
  155. */
  156. - resetCursorRects
  157. {
  158.     id            imageId, visView;
  159.  
  160.     NXPoint        hotspot;
  161.  
  162.     NXRect        cursorRect, visRect;
  163.  
  164.     if (zooming)
  165.     {
  166.         if (!zoomCursor)
  167.         {
  168.             hotspot.x = hotspot.y = 8.0;
  169.             imageId = [NXImage  newFromSection:"zoom.tiff"];
  170.             zoomCursor = [NXCursor  newFromImage:imageId];
  171.             [zoomCursor setHotSpot:&hotspot];
  172.         }
  173.  
  174.         [self getVisibleRect:&visRect];
  175.         visView = [self getDrawViewInRect:&visRect  withDrop:NO];
  176.         if (visView)
  177.         {
  178.             [visView getFrame:&cursorRect];
  179.             NXIntersectionRect(&visRect, &cursorRect);
  180.             [self addCursorRect:&cursorRect  cursor:zoomCursor];
  181.         }        
  182.         else
  183.             zooming = NO;
  184.     }
  185.  
  186.     return self;
  187. }
  188.  
  189. /*
  190. *    Messaged from the zoom matrix. Starts the zoom loop. At the next
  191. *    mouse down in the drawing view, the scaleDrawView:toPoint: method
  192. *    will be called.
  193. */
  194. - zoom:sender
  195. {
  196.     zooming = YES;
  197.     [self  setZoomControl:sender];
  198.     [self  resetCursorRects];
  199.  
  200.     [window makeKeyAndOrderFront:self];
  201.  
  202.     return self;
  203. }
  204.  
  205. /*
  206. *    Sizes the drawing view from the old scale to the newscale.
  207. *    The frame of the view is used instead of the bounds because
  208. *    the bound will always be the same whereas the frame will
  209. *    provide the size in default coordinates.
  210. */
  211. - sizeView:viewId withScale:(float) newscale
  212. {
  213.     float            scalefactor, sizewidth, sizeheight;
  214.  
  215.     NXRect        viewFrame;
  216.     
  217.     [viewId  getFrame:&viewFrame];
  218.     scalefactor = newscale/scale;
  219.     sizewidth = viewFrame.size.width*scalefactor;
  220.     sizeheight = viewFrame.size.height*scalefactor;
  221.     [viewId sizeTo:rint(sizewidth) :rint(sizeheight)];
  222.  
  223.     return self;
  224. }
  225.  
  226. /* 
  227. *    Scales the drawing view from the old scale to the new scale.
  228. *    The scale method is relative so we use the ratio
  229. *    of the old scale to the new scale to obtain the scaling factor.
  230. */
  231. - scaleView:viewId  withScale:(float) newscale
  232. {
  233.     float     scalefactor;
  234.  
  235.     scalefactor = newscale/scale;
  236.     [viewId scale:scalefactor  :scalefactor];
  237.  
  238.     return self;
  239. }
  240.  
  241. /*
  242. *    Place the view passed in in the center of the doc view
  243. *    if it is smaller than the size of the ClipView. Two passes are made
  244. *    through the loop because adding or removing a horizontal or
  245. *    vertical scrollbar will affect the size of the remaining dimension .
  246. */
  247. - placeView:viewId
  248. {
  249.     BOOL        vert = NO, horiz = NO, done = NO;
  250.  
  251.     int            passes = 0, border_type;
  252.  
  253.     float            margin;
  254.     
  255.     NXSize        contSize, newSize, insetSize, delta;
  256.  
  257.     NXRect         viewFrame, scrollFrame;
  258.  
  259.     margin = 4 * OFFSET * scale;
  260.  
  261.     [viewId  getFrame:&viewFrame];
  262.     [[superview superview]  getFrame:&scrollFrame];
  263.     border_type = [[superview superview]  borderType];
  264.  
  265.     while (!done && ++passes <= 2)
  266.     {
  267.         [ScrollView getContentSize:&contSize forFrameSize:&scrollFrame.size
  268.             horizScroller:horiz  vertScroller:vert borderType:border_type];
  269.  
  270.         newSize.width = MAX(viewFrame.size.width, contSize.width);
  271.         newSize.height = MAX(viewFrame.size.height, contSize.height);
  272.  
  273.         delta.width = newSize.width - viewFrame.size.width;
  274.         delta.height = newSize.height - viewFrame.size.height;
  275.         if (delta.width != 0.0 || delta.height != 0.0)
  276.         {
  277.             if (delta.width < margin)
  278.                 newSize.width += margin - delta.width;
  279.             if (delta.height < margin)
  280.                 newSize.height += margin - delta.height;
  281.         }
  282.  
  283.         horiz = (newSize.width != contSize.width);
  284.         vert = (newSize.height != contSize.height);
  285.         if ((horiz && vert) || (!horiz && !vert))
  286.             done = YES;
  287.         else
  288.             done = NO;
  289.     }
  290.     
  291.     [self  sizeTo:newSize.width  :newSize.height];
  292.  
  293.     insetSize.width = floor((newSize.width - viewFrame.size.width)/2);
  294.     insetSize.height =  floor((newSize.height - viewFrame.size.height)/2);
  295.     [viewId  moveTo:insetSize.width  :insetSize.height];
  296.     if (insetSize.width != 0 || insetSize.height != 0)
  297.         [viewId  setClipping:YES];
  298.     else
  299.         [viewId setClipping:NO];
  300.  
  301.     if (horiz)
  302.         [[superview superview] setHorizScrollerRequired:YES];
  303.     else
  304.         [[superview superview] setHorizScrollerRequired:NO];
  305.     
  306.     if (vert)
  307.         [[superview superview] setVertScrollerRequired:YES];
  308.     else
  309.         [[superview superview] setVertScrollerRequired:NO];
  310.  
  311.     return self;
  312. }
  313.  
  314. /*
  315. *    Scales the view to the tag of the selected matrix cell and then
  316. *    scrolls to the point. The point is in window coordinates so
  317. *    it must be converted to the drawing view  coordinates in order
  318. *    to position it in the same relative place in the view.
  319. */
  320. - scaleDrawView:hitView  toPoint:(NXPoint *) p;
  321. {
  322.     float            newscale;
  323.  
  324.     NXPoint        viewPt;
  325.  
  326.     [window invalidateCursorRectsForView:self];
  327.     newscale = [zoomControl  selectedTag] * 0.01;
  328.     if (hitView && newscale != scale)
  329.     {
  330.         viewPt = *p;
  331.         [self convertPoint:&viewPt fromView:nil];
  332.         [self convertPoint:&viewPt  toView:hitView];
  333.         [window disableDisplay];
  334.             /* Size and then scale the drawing view. The frame of the */
  335.             /* drawing view must reflect the changed size. Scaling */
  336.             /* alone will not change the frame. */
  337.             [self  sizeView:hitView  withScale:newscale];
  338.             [self  scaleView:hitView  withScale:newscale];
  339.             [self  setScale:newscale];
  340.     
  341.             [self  placeView:hitView];
  342.             [self  scrollPoint:&viewPt  inView:hitView  to:p];
  343.         [window reenableDisplay];
  344.         [[window contentView]  display];
  345.     }
  346.     zooming = NO;
  347.  
  348.     return self;
  349. }
  350.  
  351.  
  352. /*
  353.  *    Use the point location relative to the window versus the point relative
  354.  *    to the drawing view (before the scale) to determine where to scroll
  355.  *    the drawing view. We want the same location in the drawing view to
  356.  *    appear where the mouse downed occurred.  The window coordinates
  357.  *    are used and then adjusted by the position of the scrolling frame
  358.  *    because the presence or absence of scrollbars throws the use
  359.  *    of the doc views coordinates awry.
  360.  */    
  361. - scrollPoint:(const NXPoint *) aPt  inView:hitView  to:(const NXPoint *) windowPt
  362. {
  363.     NXPoint        viewPt;
  364.  
  365.     NXSize        contSize;
  366.  
  367.     NXRect         viewFrame, visRect, scrollFrame;
  368.  
  369.     [[superview superview]  getContentSize:&contSize];
  370.     [hitView  getFrame:&viewFrame];
  371.  
  372.     if (viewFrame.size.width > contSize.width || viewFrame.size.height > contSize.height)
  373.     {
  374.         viewPt = *aPt;
  375.         [self  convertPoint:&viewPt  fromView:hitView];        
  376.         [self getVisibleRect:&visRect];
  377.         [[superview superview] getFrame:&scrollFrame];
  378.  
  379.         if (viewFrame.size.width > contSize.width)
  380.             viewPt.x  -= windowPt->x - (scrollFrame.origin.x +scrollFrame.size.width -
  381.                             visRect.size.width);
  382.  
  383.         if (viewFrame.size.height > contSize.height)
  384.             viewPt.y  -= windowPt->y - (scrollFrame.origin.y + scrollFrame.size.height -
  385.                             visRect.size.height);
  386.  
  387.         [self  scrollPoint:&viewPt];        
  388.     }
  389.  
  390.     return self;
  391. }
  392.  
  393. /*
  394.  * This drawSelf method draws a border around the drawing view as well as a
  395.  * drop shadow.  This is only done if it will be visible however. We tell if it is visible
  396.  * if the rectangle passed in is not contained entirely within drawingView frame.
  397. */
  398. - drawSelf:(NXRect *)r :(int) count
  399. {
  400.     id            visView;
  401.  
  402.     NXRect        drawRect, dropRect;
  403.  
  404.     visView = [self getDrawViewInRect:r  withDrop:YES];
  405.     if (visView)
  406.     {
  407.         [visView  getFrame:&drawRect];
  408.         if (!NXContainsRect(&drawRect, r))
  409.         {
  410.             dropRect = drawRect;
  411.             NXOffsetRect(&dropRect, rint(OFFSET * scale), rint(-OFFSET * scale));
  412.  
  413.             PSgsave();
  414.             PSsetgray(NX_BLACK);
  415.             PSsetlinewidth(LINEWIDTH * scale);
  416.             PSrectclip(r->origin.x, r->origin.y, r->size.width, r->size.height);
  417.             PSrectfill(dropRect.origin.x, dropRect.origin.y,
  418.                 dropRect.size.width, dropRect.size.height);
  419.             PSrectstroke(drawRect.origin.x, drawRect.origin.y,
  420.                 drawRect.size.width, drawRect.size.height);
  421.             PSgrestore();
  422.         }
  423.     }
  424.  
  425.     return self;            
  426. }
  427.  
  428. @end
  429.  
  430.